package com.billdowney.service.impl.system.quartz;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.ScheduleBuilder;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.quartz.QuartzProperties;
import org.springframework.stereotype.Service;

import com.billdowney.annotation.quartz.JobClassDesc;
import com.billdowney.annotation.quartz.JobClassParam;
import com.billdowney.dao.system.log.SystemLogDao;
import com.billdowney.entity.system.log.SystemLog;
import com.billdowney.exception.BizException;
import com.billdowney.service.impl.base.BaseServiceImpl;
import com.billdowney.service.interfaces.system.quartz.QuartzManageService;
import com.billdowney.util.CommonUtil;
import com.billdowney.util.quartz.QuartzConst;
import com.billdowney.util.spring.SpringUtil;
import com.billdowney.vo.system.quartz.JobDetailInfoVO;
import com.billdowney.vo.system.quartz.JobTriggerInfoVO;

/**
 * quartz定时任务管理接口实现
 * 
 * @author 超级小富翁 - BillDowney
 * @date 2019年9月5日 上午11:04:49
 */
@Service
public class QuartzManageServiceImpl extends BaseServiceImpl<SystemLogDao, SystemLog, String>
		implements QuartzManageService {

	@Resource(type = SystemLogDao.class)
	@Override
	public void setDao(SystemLogDao dao) {
		super.dao = dao;
	}

	// 系统配置的调度器
	@Autowired
	private Scheduler scheduler;
	// 配置的参数
	@Autowired
	private QuartzProperties quartzProperties;

	@Override
	public QuartzProperties getQuartzProperties() {
		return quartzProperties;
	}

	@Override
	public List<JobDetailInfoVO> getAllJobClass() {
		Map<String, Job> map = SpringUtil.getBeansOfType(Job.class);
		if (CommonUtil.isNotEmpty(map)) {
			List<JobDetailInfoVO> list = new ArrayList<JobDetailInfoVO>();
			for (String key : map.keySet()) {
				Class<? extends Job> job = map.get(key).getClass();
				JobDetailInfoVO info = new JobDetailInfoVO();
				// 设置名称
				info.setJobName(job.getName());
				// 设置组名
				info.setJobGroup(QuartzConst.JOB_GROUP_NAME);
				// 设置类名
				info.setJobClass(job.getName());
				// 设置描述
				if (job.isAnnotationPresent(JobClassDesc.class)) {
					JobClassDesc desc = job.getAnnotation(JobClassDesc.class);
					info.setJobDesc(desc.value());
					info.addParamList(desc.params());
				}
				// 设置参数
				if (job.isAnnotationPresent(JobClassParam.class)) {
					info.addParamList(job.getAnnotation(JobClassParam.class));
				}
				list.add(info);
			}
			return list;
		}
		return null;
	}

	@Override
	public JobDetailInfoVO getJobDetailInfo(JobKey jobKey) {
		JobDetailInfoVO info = new JobDetailInfoVO();
		try {
			this.checkExists(jobKey);
			// 获取所有的JobKey
			JobDetail jobDetail = scheduler.getJobDetail(jobKey);
			info.setJobClass(jobDetail.getJobClass().getName());
			info.setJobDesc(jobDetail.getDescription());
			info.setJobName(jobDetail.getKey().getName());
			info.setJobGroup(jobDetail.getKey().getGroup());
		} catch (SchedulerException e) {
			throw new BizException(10703, e);
		}
		return info;
	}

	@Override
	public List<JobDetailInfoVO> getSchedulerJobDetailList() {
		List<JobDetailInfoVO> list = new ArrayList<JobDetailInfoVO>();
		try {
			// 获取所有的JobKey
			Set<JobKey> keys = scheduler.getJobKeys(GroupMatcher.anyJobGroup());
			for (JobKey jobKey : keys) {
				list.add(this.getJobDetailInfo(jobKey));
			}
		} catch (SchedulerException e) {
			throw new BizException(10705, e);
		}
		return list;
	}

	@Override
	public List<JobTriggerInfoVO> getJobTriggerList(JobKey jobKey) {
		List<JobTriggerInfoVO> list = new ArrayList<JobTriggerInfoVO>();
		try {
			this.checkExists(jobKey);
			List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
			for (Trigger trigger : triggers) {
				JobTriggerInfoVO info = new JobTriggerInfoVO();
				info.setJobName(trigger.getJobKey().getName());
				info.setJobGroup(trigger.getJobKey().getGroup());
				info.setTriggerName(trigger.getKey().getName());
				info.setTriggerGroup(trigger.getKey().getGroup());
				info.setCalendarName(trigger.getCalendarName());
				info.setDesc(trigger.getDescription());
				info.setJobDataMap(scheduler.getJobDetail(jobKey).getJobDataMap().getWrappedMap());
				info.setTriggerDataMap(trigger.getJobDataMap().getWrappedMap());
				info.setPriority(trigger.getPriority());
				info.setStartTime(trigger.getStartTime());
				info.setEndTime(trigger.getEndTime());
				info.setPreviousFireTime(trigger.getPreviousFireTime());
				info.setNextFireTime(trigger.getNextFireTime());
				info.setFinalFireTime(trigger.getFinalFireTime());
				info.setState(scheduler.getTriggerState(trigger.getKey()));
				list.add(info);
			}
		} catch (SchedulerException e) {
			throw new BizException(10706, e);
		}
		return list;
	}

	@SuppressWarnings("unchecked")
	@Override
	public JobDetailInfoVO addJob(JobDetailInfoVO infoVO, boolean replace) {
		CommonUtil.isNotEmpty(infoVO.getJobClass(), new BizException(10702));
		CommonUtil.isNotEmpty(infoVO.getJobName(), new BizException(10709));
		try {
			Class<Job> clazz = (Class<Job>) Class.forName(infoVO.getJobClass());
			JobBuilder jobBuilder = JobBuilder.newJob(clazz);
			// 添加作业名和作业组名
			if (CommonUtil.isEmpty(infoVO.getJobGroup())) {
				jobBuilder.withIdentity(infoVO.getJobName(), QuartzConst.JOB_GROUP_NAME);
			} else {
				jobBuilder.withIdentity(infoVO.getJobName(), infoVO.getJobGroup());
			}
			// 添加描述
			if (CommonUtil.isEmpty(infoVO.getJobDesc())) {
				jobBuilder.withDescription(infoVO.getJobDesc());
			}
			// 持久化作业
			JobDetail jobDetail = jobBuilder.storeDurably().build();
			scheduler.addJob(jobDetail, replace);
			return this.getJobDetailInfo(jobDetail.getKey());
		} catch (ClassNotFoundException e) {
			throw new BizException(10703, e);
		} catch (SchedulerException e) {
			throw new BizException(10704, e);
		}
	}

	@Override
	public void pauseTrigger(TriggerKey triggerKey) {
		try {
			this.checkExists(triggerKey);
			scheduler.pauseTrigger(triggerKey);
		} catch (SchedulerException e) {
			throw new BizException(10713, e);
		}
	}

	@Override
	public boolean unscheduleJob(TriggerKey triggerKey) {
		try {
			this.pauseTrigger(triggerKey);
			return scheduler.unscheduleJob(triggerKey);
		} catch (SchedulerException e) {
			throw new BizException(10714, e);
		}
	}

	@Override
	public void resumeTrigger(TriggerKey triggerKey) {
		try {
			this.checkExists(triggerKey);
			scheduler.resumeTrigger(triggerKey);
		} catch (SchedulerException e) {
			throw new BizException(10715, e);
		}
	}

	@Override
	public void pauseJob(JobKey jobKey) {
		try {
			this.checkExists(jobKey);
			scheduler.pauseJob(jobKey);
		} catch (SchedulerException e) {
			throw new BizException(10716, e);
		}
	}

	@Override
	public boolean deleteJob(JobKey jobKey) {
		try {
			this.pauseJob(jobKey);
			return scheduler.deleteJob(jobKey);
		} catch (SchedulerException e) {
			throw new BizException(10717, e);
		}
	}

	@Override
	public JobTriggerInfoVO scheduleJob(JobTriggerInfoVO info, JobKey jobKey,
			ScheduleBuilder<Trigger> scheduleBuilder) {
		this.checkExists(jobKey);
		CommonUtil.isNotEmpty(info.getTriggerName(), new BizException(10720));
		CommonUtil.isNotEmpty(scheduleBuilder, new BizException(10722));
		TriggerKey triggerKey = null;
		if (CommonUtil.isEmpty(info.getTriggerGroup())) {
			triggerKey = new TriggerKey(info.getTriggerName(), QuartzConst.TRIGGER_GROUP_NAME);
		} else {
			triggerKey = new TriggerKey(info.getTriggerName(), info.getTriggerGroup());
		}
		// 检查是否存在相同的triggerKey
		try {
			if (scheduler.checkExists(triggerKey)) {
				throw new BizException(10721);
			}
		} catch (SchedulerException e1) {
			throw new BizException(10719, e1);
		}
		try {
			TriggerBuilder<Trigger> builder = TriggerBuilder.newTrigger().withIdentity(triggerKey);
			// 设置参数
			if (CommonUtil.isNotEmpty(info.getTriggerDataMap())) {
				builder.usingJobData(new JobDataMap(info.getTriggerDataMap()));
			}
			// 设置开始时间
			if (CommonUtil.isNotEmpty(info.getStartTime())) {
				builder.startAt(info.getStartTime());
			}
			// 设置结束时间
			if (CommonUtil.isNotEmpty(info.getEndTime())) {
				builder.endAt(info.getEndTime());
			}
			// 设置描述
			if (CommonUtil.isNotEmpty(info.getDesc())) {
				builder.withDescription(info.getDesc());
			}
			// 设置优先级
			if (CommonUtil.isNotEmpty(info.getPriority())) {
				builder.withPriority(info.getPriority().intValue());
			}
			builder.forJob(jobKey);
			builder.withSchedule(scheduleBuilder);
			scheduler.scheduleJob(builder.build());
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
		return info;
	}

	/**
	 * 检查传入的JobKey是否存在
	 * 
	 * @param jobKey 作业的唯一标识
	 * @throws SchedulerException
	 * @author: 超级小富翁 - BillDowney
	 * @date: 2019年9月24日 上午10:40:20
	 */
	private void checkExists(JobKey jobKey) {
		CommonUtil.isNotEmpty(jobKey, new BizException(10701));
		try {
			if (scheduler.checkExists(jobKey) == false) {
				throw new BizException(10710);
			}
		} catch (SchedulerException e) {
			throw new BizException(10711, e);
		}
	}

	/**
	 * 检查传入的triggerKey是否存在
	 * 
	 * @param triggerKey 触发器的唯一标识
	 * @throws SchedulerException
	 * @author: 超级小富翁 - BillDowney
	 * @date: 2019年9月24日 上午10:42:46
	 */
	private void checkExists(TriggerKey triggerKey) {
		CommonUtil.isNotEmpty(triggerKey, new BizException(10707));
		try {
			if (scheduler.checkExists(triggerKey) == false) {
				throw new BizException(10712);
			}
		} catch (SchedulerException e) {
			throw new BizException(10719, e);
		}
	}

}
